package ds.factcom.model;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;

import javax.swing.table.TableModel;

import ds.factcom.domain.client.Client;
import ds.factcom.domain.invoice.Invoice;
import ds.factcom.domain.invoice.InvoiceCompany;
import ds.factcom.domain.invoice.InvoicePerson;
import ds.factcom.domain.invoice.InvoiceVip;
import ds.factcom.domain.item.Item;
import ds.factcom.domain.product.Product;
import ds.factcom.exception.ClientHasNotInvoices;
import ds.factcom.exception.ClientHasNotInvoicesPending;
import ds.factcom.exception.EmptyListProductException;
import ds.factcom.exception.ExistDomainException;
import ds.factcom.exception.NotDefinedClientException;
import ds.factcom.exception.NotExistDomainException;

/**
 * 
 * @author Javier De Luca, Maximiliano Herrera, Matias Samblancat
 *
 */
public class InvoiceModel extends Observable {

	private final ClientModel clientModel;
	private final ProductModel productModel;
	
	private Invoice invoice;
	private List<Item> items;
	private TableModel itemTableModel;
	
	private List<Object> listData;
	private TableModel mountTableModel;

	public InvoiceModel(ClientModel clientModel, ProductModel productModel) {
		this.clientModel = clientModel;
		this.productModel = productModel;
		this.items = new ArrayList<Item>();
		this.itemTableModel = new ItemTableModel(this);
		this.mountTableModel = new MountTableModel(this);
		listData = new ArrayList<Object>();
	}

	public void findByDescription(String description) throws NotExistDomainException {
		this.productModel.findByDescription(description);
	}
	
	public void addProduct(String description, int cant) throws NotExistDomainException {
		findByDescription(description);
		Item item = new Item(this.productModel.getProduct(), cant);
		this.getItems().add(item);
		notifier(Message.PRODUCT_ADDED_SUCCESS);
	}

	public void findByDocument(String documentType, String documentNumber) throws NotExistDomainException {
		this.clientModel.findByDocument(documentType, documentNumber);
		notifier(Message.CLIENT_FOUND);
	}

	public List<Invoice> findClientWithPendingInvoices(String documentType, String documentNumber) throws NotExistDomainException, ClientHasNotInvoices, ClientHasNotInvoicesPending {
		this.findByDocument(documentType, documentNumber);
		return this.clientModel.findClientWithPendingInvoices();
	}
	
	public Client getClient(){
		return this.clientModel.getClient();
	}
	
	public void findInvoice(Invoice newInvoice) throws ExistDomainException, NotExistDomainException {
		for (Iterator<Invoice> iterator = getClient().getInvoices().iterator(); iterator.hasNext();) {
			Invoice invoice = (Invoice) iterator.next();
			if (invoice.equals(newInvoice)){
				throw new ExistDomainException("Factura");
			}else{
				throw new NotExistDomainException("La factura");
			}
		}
	}

	public void generateInvioceVip() throws EmptyListProductException, NotDefinedClientException {
		if (this.clientModel.getClient() != null) {
			if(!this.getItems().isEmpty()){
				this.invoice = new InvoiceVip(this.clientModel.getClient(), getItems());
				addComplementation();
			}else{
				throw new EmptyListProductException();
			}
		} else {
			throw new NotDefinedClientException();
		}
	}

	public void generateInviocePerson() throws EmptyListProductException, NotDefinedClientException {
		if (this.clientModel.getClient() != null) {
			if(!this.getItems().isEmpty()){
				this.invoice = new InvoicePerson(this.clientModel.getClient(), getItems());
				addComplementation();
			}else{
				throw new EmptyListProductException();
			}
		} else {
			throw new NotDefinedClientException();
		}
	}

	public void generateInvoiceCompany() throws EmptyListProductException, NotDefinedClientException {
		if (this.clientModel.getClient() != null) {
			if(!this.getItems().isEmpty()){
				this.invoice = new InvoiceCompany(this.clientModel.getClient(), getItems());
				addComplementation();
			} else {
				throw new EmptyListProductException();
			}
		} else {
			throw new NotDefinedClientException();
		}
	}

	private void addComplementation() {
		this.clientModel.getClient().getInvoices().add(this.invoice);
		this.productModel.getProduct().getInvoices().add(this.invoice);
		createListData();
		this.notifier(Message.INVOICE_CREATED);
	}

	private void notifier(String string) {
		this.setChanged();
		this.notifyObservers(string);
	}
	
	public Invoice getInvoice() {
		return invoice;
	}

	public void setInvoice(Invoice invoice) {
		this.invoice = invoice;
	}

	public void setProduct(Product product) {
		this.productModel.setProduct(product);
	}

	public String getProductDescription() {
		return this.productModel.getProduct().getDescription();
	}

	public boolean existProduct(){
		return this.productModel.existProduct();
	} 
	
	public String getClientName() {
		return this.getClient().getName();
	}
	
	public String getClientAddress() {
		return this.getClient().getAddress();
	}
	
	public String getClientDocumentNumber() {
		return this.getClient().getDocument().getNumber();
	}
	
	public String getClientDocumentType() {
		return this.getClient().getDocument().getDocumentType().getValue();
	}

	public List<Item> getItems() {
		return items;
	}

	public TableModel getItemTableModel() {
		return itemTableModel;
	}

	public void removeItems() {
		this.items.clear();
		this.listData.clear();
	}

	public TableModel getMountTableModel() {
		return mountTableModel;
	}

	public List<Object> getListData() {
		return listData;
	}
	
	private void createListData() {
		listData.add("Monto Neto");
		listData.add(this.invoice.getMountNet());
		listData.add("Monto Total");
		listData.add(this.invoice.getMountAbsoluty());
	}

	public void cleanClient() {

		this.clientModel.setClient(null);
	}
}
